الگوی کارخانه عمومی برای ایجاد نوع اشیاء ایمن در توسعه نرمافزار را بررسی کنید. نحوه بهبود نگهداری کد، کاهش خطاها و بهبود طراحی کلی را بیاموزید.
الگوی کارخانه عمومی: دستیابی به ایمنی نوع در ایجاد اشیاء
الگوی کارخانه یک الگوی طراحی خلاقانه است که رابطی را برای ایجاد اشیاء بدون مشخص کردن کلاسهای ملموس آنها فراهم میکند. این به شما امکان میدهد کد مشتری را از فرآیند ایجاد اشیاء جدا کنید و کد را انعطافپذیرتر و قابل نگهداریتر کنید. با این حال، الگوی کارخانه سنتی گاهی اوقات ممکن است فاقد ایمنی نوع باشد و به طور بالقوه منجر به خطاهای زمان اجرا شود. الگوی کارخانه عمومی با بهرهگیری از جنریکها برای اطمینان از ایجاد نوع ایمن اشیاء، این محدودیت را برطرف میکند.
الگوی کارخانه عمومی چیست؟
الگوی کارخانه عمومی توسعهای از الگوی کارخانه استاندارد است که از جنریکها برای اجبار به ایمنی نوع در زمان کامپایل استفاده میکند. این تضمین میکند که اشیاء ایجاد شده توسط کارخانه با نوع مورد انتظار مطابقت دارند و از خطاهای غیرمنتظره در زمان اجرا جلوگیری میکند. این امر به ویژه در زبانهایی که از جنریکها پشتیبانی میکنند، مانند C#، Java و TypeScript مفید است.
مزایای استفاده از الگوی کارخانه عمومی
- ایمنی نوع: تضمین میکند که اشیاء ایجاد شده از نوع صحیح هستند و خطر خطاهای زمان اجرا را کاهش میدهد.
- نگهداری کد: ایجاد اشیاء را از کد مشتری جدا میکند و اصلاح یا گسترش کارخانه را بدون تأثیر بر مشتری آسانتر میکند.
- انعطافپذیری: به شما امکان میدهد به راحتی بین پیادهسازیهای مختلف از یک رابط یا کلاس انتزاعی جابجا شوید.
- کاهش کد تکراری: با کپسولهسازی منطق ایجاد اشیاء در کارخانه، میتواند آن را ساده کند.
- قابلیت تست بهبود یافته: با اجازه دادن به شما برای شبیهسازی یا جایگزینی آسان کارخانه، تست واحد را تسهیل میکند.
پیادهسازی الگوی کارخانه عمومی
پیادهسازی الگوی کارخانه عمومی معمولاً شامل تعریف یک رابط یا کلاس انتزاعی برای اشیاء مورد نظر برای ایجاد و سپس ایجاد یک کلاس کارخانه است که از جنریکها برای اطمینان از ایمنی نوع استفاده میکند. در اینجا نمونههایی به زبانهای C#، Java و TypeScript آورده شده است.
مثال در C#
سناریویی را در نظر بگیرید که در آن نیاز به ایجاد انواع مختلف لاگر بر اساس تنظیمات پیکربندی دارید.
// تعریف رابط برای لاگرها
public interface ILogger
{
void Log(string message);
}
// پیادهسازیهای ملموس لاگرها
public class ConsoleLogger : ILogger
{
public void Log(string message)
{
Console.WriteLine($"Console: {message}");
}
}
public class FileLogger : ILogger
{
private readonly string _filePath;
public FileLogger(string filePath)
{
_filePath = filePath;
}
public void Log(string message)
{
File.AppendAllText(_filePath, $"{DateTime.Now}: {message}\n");
}
}
// رابط کارخانه عمومی
public interface ILoggerFactory
{
T CreateLogger() where T : ILogger;
}
// پیادهسازی کارخانه ملموس
public class LoggerFactory : ILoggerFactory
{
public T CreateLogger() where T : ILogger
{
if (typeof(T) == typeof(ConsoleLogger))
{
return (T)(ILogger)new ConsoleLogger();
}
else if (typeof(T) == typeof(FileLogger))
{
// ایده آل است که مسیر فایل را از پیکربندی بخوانید
return (T)(ILogger)new FileLogger("log.txt");
}
else
{
throw new ArgumentException($"نوع لاگر پشتیبانی نشده: {typeof(T).Name}");
}
}
}
// استفاده
public class MyApplication
{
private readonly ILogger _logger;
public MyApplication(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger();
}
public void DoSomething()
{
_logger.Log("Doing something...");
}
}
در این مثال C#، رابط ILoggerFactory و کلاس LoggerFactory از جنریکها برای اطمینان از بازگرداندن صحیح نوع شیء توسط متد CreateLogger استفاده میکنند. محدودیت where T : ILogger تضمین میکند که فقط کلاسهایی که رابط ILogger را پیادهسازی میکنند میتوانند توسط کارخانه ایجاد شوند.
مثال در جاوا
در اینجا پیادهسازی جاوا از الگوی کارخانه عمومی برای ایجاد انواع مختلف اشکال آورده شده است.
// تعریف رابط برای اشکال
interface Shape {
void draw();
}
// پیادهسازیهای ملموس اشکال
class Circle implements Shape {
@Override
public void draw() {
System.out.println("Drawing a circle");
}
}
class Square implements Shape {
@Override
public void draw() {
System.out.println("Drawing a square");
}
}
// رابط کارخانه عمومی
interface ShapeFactory {
<T extends Shape> T createShape(Class<T> shapeType);
}
// پیادهسازی کارخانه ملموس
class DefaultShapeFactory implements ShapeFactory {
@Override
public <T extends Shape> T createShape(Class<T> shapeType) {
try {
return shapeType.getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new IllegalArgumentException("Cannot create shape of type: " + shapeType.getName(), e);
}
}
}
// استفاده
public class Main {
public static void main(String[] args) {
ShapeFactory factory = new DefaultShapeFactory();
Circle circle = factory.createShape(Circle.class);
circle.draw();
Square square = factory.createShape(Square.class);
square.draw();
}
}
در این مثال جاوا، رابط ShapeFactory و کلاس DefaultShapeFactory از جنریکها برای اجازه دادن به مشتری برای تعیین نوع دقیق Shape برای ایجاد استفاده میکنند. استفاده از Class<T> و انعکاس، راهی انعطافپذیر برای نمونهسازی انواع مختلف شکل بدون نیاز به دانستن صریح هر کلاس در خود کارخانه فراهم میکند.
مثال در تایپاسکریپت
در اینجا پیادهسازی تایپاسکریپت برای ایجاد انواع مختلف اعلانها آورده شده است.
// تعریف رابط برای اعلانها
interface INotification {
send(message: string): void;
}
// پیادهسازیهای ملموس اعلانها
class EmailNotification implements INotification {
private readonly emailAddress: string;
constructor(emailAddress: string) {
this.emailAddress = emailAddress;
}
send(message: string): void {
console.log(`Sending email to ${this.emailAddress}: ${message}`);
}
}
class SMSNotification implements INotification {
private readonly phoneNumber: string;
constructor(phoneNumber: string) {
this.phoneNumber = phoneNumber;
}
send(message: string): void {
console.log(`Sending SMS to ${this.phoneNumber}: ${message}`);
}
}
// رابط کارخانه عمومی
interface INotificationFactory {
createNotification<T extends INotification>(): T;
}
// پیادهسازی کارخانه ملموس
class NotificationFactory implements INotificationFactory {
createNotification<T extends INotification>(): T {
if (typeof T === typeof EmailNotification) {
return new EmailNotification("test@example.com") as T;
} else if (typeof T === typeof SMSNotification) {
return new SMSNotification("+15551234567") as T;
} else {
throw new Error(`Unsupported notification type: ${typeof T}`);
}
}
}
// استفاده
const factory = new NotificationFactory();
const emailNotification = factory.createNotification<EmailNotification>();
emailNotification.send("Hello from email!");
const smsNotification = factory.createNotification<SMSNotification>();
smsNotification.send("Hello from SMS!");
در این مثال تایپاسکریپت، رابط INotificationFactory و کلاس NotificationFactory از جنریکها برای اجازه دادن به مشتری برای تعیین نوع دقیق INotification برای ایجاد استفاده میکنند. کارخانه با ایجاد نمونههایی از کلاسهایی که رابط INotification را پیادهسازی میکنند، ایمنی نوع را تضمین میکند. استفاده از typeof T برای مقایسه یک الگوی رایج تایپاسکریپت است.
چه زمانی از الگوی کارخانه عمومی استفاده کنیم
الگوی کارخانه عمومی به ویژه در سناریوهایی مفید است که:
- نیاز به ایجاد انواع مختلف اشیاء بر اساس شرایط زمان اجرا دارید.
- میخواهید ایجاد اشیاء را از کد مشتری جدا کنید.
- برای جلوگیری از خطاهای زمان اجرا به ایمنی نوع در زمان کامپایل نیاز دارید.
- نیاز به جابجایی آسان بین پیادهسازیهای مختلف از یک رابط یا کلاس انتزاعی دارید.
- با زبانی کار میکنید که از جنریکها پشتیبانی میکند، مانند C#، Java یا TypeScript.
اشتباهات و ملاحظات رایج
- مهندسی بیش از حد: از الگوی کارخانه در مواردی که ایجاد اشیاء ساده کافی است، اجتناب کنید. استفاده بیش از حد از الگوهای طراحی میتواند منجر به پیچیدگی غیرضروری شود.
- پیچیدگی کارخانه: با افزایش تعداد انواع اشیاء، پیادهسازی کارخانه میتواند پیچیده شود. برای مدیریت پیچیدگی، الگوی کارخانه پیشرفتهتری مانند الگوی کارخانه انتزاعی را در نظر بگیرید.
- سربار انعکاس (جاوا): استفاده از انعکاس برای ایجاد اشیاء در جاوا میتواند سربار عملکرد داشته باشد. نمونههای ایجاد شده را ذخیره کنید یا برای برنامههای کاربردی با عملکرد حیاتی از مکانیزم ایجاد شیء متفاوتی استفاده کنید.
- پیکربندی: پیکربندی خارجی انواع اشیاء برای ایجاد را در نظر بگیرید. این به شما امکان میدهد منطق ایجاد شیء را بدون تغییر کد تغییر دهید. برای مثال، ممکن است نام کلاسها را از یک فایل خصوصیات بخوانید.
- مدیریت خطا: اطمینان حاصل کنید که مدیریت خطای مناسب در کارخانه برای رسیدگی به موارد شکست ایجاد شیء به صورت موثر انجام میشود. پیامهای خطای آموزنده برای کمک به اشکالزدایی ارائه دهید.
جایگزینهای الگوی کارخانه عمومی
در حالی که الگوی کارخانه عمومی ابزار قدرتمندی است، رویکردهای جایگزینی برای ایجاد اشیاء وجود دارد که ممکن است در شرایط خاص مناسبتر باشند.
- تزریق وابستگی (DI): چارچوبهای DI میتوانند ایجاد اشیاء و وابستگیها را مدیریت کنند و نیاز به کارخانههای صریح را کاهش دهند. DI به ویژه در برنامههای بزرگ و پیچیده مفید است. چارچوبهایی مانند Spring (Java)، .NET DI Container (C#) و Angular (TypeScript) قابلیتهای قوی DI را ارائه میدهند.
- الگوی کارخانه انتزاعی: الگوی کارخانه انتزاعی رابطی را برای ایجاد خانوادههایی از اشیاء مرتبط بدون مشخص کردن کلاسهای ملموس آنها فراهم میکند. این زمانی مفید است که نیاز به ایجاد چندین شیء مرتبط دارید که بخشی از یک خانواده محصول منسجم هستند.
- الگوی سازنده: الگوی سازنده ساخت یک شیء پیچیده را از نمایش آن جدا میکند و به شما امکان میدهد نمایشهای مختلفی از همان شیء را با استفاده از همان فرآیند ساخت ایجاد کنید.
- الگوی نمونه اولیه: الگوی نمونه اولیه به شما امکان میدهد اشیاء جدید را با کپی کردن اشیاء موجود (نمونههای اولیه) ایجاد کنید. این زمانی مفید است که ایجاد اشیاء جدید پرهزینه یا پیچیده باشد.
مثالهای دنیای واقعی
- کارخانههای اتصال پایگاه داده: ایجاد انواع مختلف اتصالات پایگاه داده (مانند MySQL، PostgreSQL، Oracle) بر اساس تنظیمات پیکربندی.
- کارخانههای درگاه پرداخت: ایجاد پیادهسازیهای مختلف درگاه پرداخت (مانند PayPal، Stripe، Visa) بر اساس روش پرداخت انتخاب شده.
- کارخانههای عناصر رابط کاربری: ایجاد عناصر مختلف رابط کاربری (مانند دکمهها، فیلدهای متن، برچسبها) بر اساس تم رابط کاربری یا پلتفرم.
- کارخانههای گزارشدهی: تولید انواع مختلف گزارشها (مانند PDF، Excel، CSV) بر اساس فرمت انتخاب شده.
این مثالها تطبیقپذیری الگوی کارخانه عمومی را در دامنههای مختلف، از دسترسی به دادهها گرفته تا توسعه رابط کاربری، نشان میدهند.
نتیجهگیری
الگوی کارخانه عمومی ابزاری ارزشمند برای دستیابی به ایجاد نوع ایمن اشیاء در توسعه نرمافزار است. با بهرهگیری از جنریکها، تضمین میکند که اشیاء ایجاد شده توسط کارخانه با نوع مورد انتظار مطابقت دارند، خطر خطاهای زمان اجرا را کاهش میدهد و نگهداری کد را بهبود میبخشد. در حالی که ضروری است معایب بالقوه و جایگزینهای آن را در نظر گرفت، الگوی کارخانه عمومی میتواند طراحی و استحکام برنامههای شما را به طور قابل توجهی بهبود بخشد، به ویژه هنگام کار با زبانهایی که از جنریکها پشتیبانی میکنند. همیشه به یاد داشته باشید که مزایای الگوهای طراحی را با نیاز به سادگی و قابلیت نگهداری در کدبیس خود متعادل کنید.